package com.bruce.spring.http.service.cgroup;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 容器CPU监控工具类（优化线程安全逻辑）
 */
public class ContainerCpuMonitor implements CpuUsageProvider {
    private static final Logger log = LoggerFactory.getLogger(ContainerCpuMonitor.class);

    // cgroup版本标识文件路径
    private static final String CGROUP_V2_MARKER = "/sys/fs/cgroup/cgroup.controllers";

    private final CpuUsageProvider provider;
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    // 仅currentCpuUsage可能被外部高并发访问，需线程安全处理
    private volatile double currentCpuUsage = 0.0;
    private volatile double currentCpuUsage2 = 0.0;

    // 以下变量仅由定时任务线程操作（单线程），无需加锁
    private long lastCpuTime = -1;  // 上次CPU时间戳（纳秒）
    private long lastJdkTime = -1;  // 上次JDK运行时间戳（毫秒）
    private int intervalMillis;     // 采样间隔（毫秒）
    private boolean isMonitoring = false;

    double totalAvailableTime;

    private static final ContainerCpuMonitor INSTANCE;

    static {
        try {
            INSTANCE = new ContainerCpuMonitor();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static ContainerCpuMonitor getInstance() {
        return INSTANCE;
    }

    /**
     * 初始化监控器
     */
    private ContainerCpuMonitor() throws IOException {
        // 检测cgroup版本
        boolean isCgroupV2 = isCgroupV2();

        // 初始化对应版本的处理器
        this.provider = isCgroupV2 ?
                new CgroupV2ProviderWithChannel() :
                new CgroupV1ProviderWithChannel();
    }

    /**
     * 启动监控
     *
     * @param intervalMillis 采样间隔（毫秒）
     */
    public synchronized void startMonitoring(int intervalMillis) {
        if (isMonitoring) {
            return;
        }
        this.intervalMillis = intervalMillis;
        this.isMonitoring = true;
        this.lastCpuTime = -1;  // 重置采样状态
        this.currentCpuUsage = 0.0;

        this.totalAvailableTime = provider.getAllocatableCores() * intervalMillis * 1_000_000L;

        // 启动定时任务（单线程执行，避免并发问题）
        scheduler.scheduleAtFixedRate(
                this::sampleAndCalculate,
                0,
                intervalMillis,
                TimeUnit.MILLISECONDS
        );
    }

    /**
     * 停止监控
     */
    public synchronized void stopMonitoring() {
        if (!isMonitoring) {
            return;
        }
        isMonitoring = false;
        scheduler.shutdown();
        try {
            if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            scheduler.shutdownNow();
        }
    }

    /**
     * 检查是否正在监控
     */
    public synchronized boolean isMonitoring() {
        return isMonitoring;
    }

    /**
     * 获取当前CPU利用率
     */
    public double getCurrentCpuUsage() {
        return currentCpuUsage;  // volatile保证可见性
    }

    /**
     * 获取当前CPU利用率, 第二种计算 方法
     */
    public double getCurrentCpuUsage2() {
        return currentCpuUsage2;  // volatile保证可见性
    }

    /**
     * 获取可分配的CPU核心数
     */
    public double getAllocatableCores() {
        return provider.getAllocatableCores();
    }

    /**
     * 获取当前CPU累计时间（纳秒）
     */
    public long getCurrentCpuTime() throws IOException {
        return provider.getCurrentCpuTime();
    }

    /**
     * 采样并计算CPU利用率（仅由定时任务单线程执行）
     */
    private void sampleAndCalculate() {
        try {
            long currentTime = provider.getCurrentCpuTime();
            long currentJdkTime = System.nanoTime();

            if (lastCpuTime == -1) {
                // 第一次采样，仅记录时间
                lastCpuTime = currentTime;
                lastJdkTime = currentJdkTime;
                currentCpuUsage = 0.0;
            } else {
                // 计算时间差（纳秒）
                long deltaTime = currentTime - lastCpuTime;
                double totalAvailableTime2 = provider.getAllocatableCores() * (currentJdkTime - lastJdkTime);
                lastCpuTime = currentTime;
                lastJdkTime = currentJdkTime;

                // 计算利用率（核心数 × 间隔毫秒 × 1e6 = 总可用纳秒）

                double usage = totalAvailableTime == 0 ? 0.0 : (deltaTime / totalAvailableTime) * 100;
                double usage2 = totalAvailableTime2 == 0 ? 0.0 : (deltaTime / totalAvailableTime2) * 100;

                // 确保结果非负（避免异常情况）
                currentCpuUsage = Math.max(0, usage);
                currentCpuUsage2 = Math.max(0, usage2);

                log.info("totalAvailableTime: {}, totalAvailableTime2:{}, usage:{}, usage2:{}",
                        totalAvailableTime, totalAvailableTime2, usage, usage2);

            }
        } catch (Exception e) {
            // 异常时重置采样状态（单线程操作，无需同步）
            lastCpuTime = -1;
            currentCpuUsage = 0.0;
            currentCpuUsage2 = 0.0;
            log.error("采样异常，已重置采样状态:", e);
        }
    }

    /**
     * 检测cgroup版本
     */
    public boolean isCgroupV2() {
        File v2Marker = new File(CGROUP_V2_MARKER);
        return v2Marker.exists() && v2Marker.canRead();
    }

}